package pebbledb

import (
	"container/list"
	"github.com/cockroachdb/pebble"
	"io"
)

type PebbleDB struct {
	db *pebble.DB
}

func NewDefaultPebbleDB(path string) (*PebbleDB, error) {
	return NewPebbleDB(path, &pebble.Options{Cache: pebble.NewCache(1024 * 1024 * 1024), DisableWAL: false})
}

func NewPebbleDB(path string, opts *pebble.Options) (*PebbleDB, error) {
	db, err := pebble.Open(path, opts)
	if err != nil {
		return nil, err
	}
	return &PebbleDB{db: db}, nil
}

//---------------private-methods--------------

func (this *PebbleDB) set(key []byte, value []byte, opts *pebble.WriteOptions) error {
	return this.db.Set(key, value, opts)
}

func (this *PebbleDB) delete(key []byte, opts *pebble.WriteOptions) error {
	return this.db.Delete(key, opts)
}

//--------------------------------------------

func (this *PebbleDB) Set(key []byte, value []byte) error {
	return this.set(key, value, pebble.Sync)
}

func (this *PebbleDB) Delete(key []byte) error {
	return this.delete(key, pebble.Sync)
}

func (this *PebbleDB) Get(key []byte) (data []byte, err error) {
	data, _, err = this.GetFull(key)
	return
}

func (this *PebbleDB) SetNoSync(key []byte, value []byte) error {
	return this.set(key, value, pebble.NoSync)
}

func (this *PebbleDB) DeleteNoSync(key []byte) error {
	return this.delete(key, pebble.NoSync)
}

func (this *PebbleDB) GetFull(key []byte) (data []byte, closer io.Closer, err error) {
	data, closer, err = this.db.Get(key)
	return
}

func (this *PebbleDB) ContainsData() bool {
	iter := this.db.NewIter(nil)
	iter.SeekGE(nil)
	return iter.Valid()
}

func (this *PebbleDB) Count() int {
	count := 0
	iter := this.db.NewIter(nil)
	iter.SeekGE(nil)
	for iter.Valid() {
		count++
		iter.Next()
	}
	return count
}

func (this *PebbleDB) List() *list.List {
	theList := list.New()
	iter := this.db.NewIter(nil)
	iter.SeekGE(nil)
	for iter.Valid() {
		value := iter.Value()
		theList.PushBack(string(value))

		iter.Next()
	}
	return theList
}

func (this *PebbleDB) Table() map[string]string {
	table := make(map[string]string)
	iter := this.db.NewIter(nil)
	iter.SeekGE(nil)
	for iter.Valid() {
		key := iter.Key()
		value := iter.Value()

		table[string(key)] = string(value)

		iter.Next()
	}
	return table
}

func (this *PebbleDB) Clear() {
	iter := this.db.NewIter(nil)
	iter.SeekGE(nil)
	for iter.Valid() {
		key := iter.Key()
		this.Delete(key)
		iter.Next()
	}
}
